package jsc.acid;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;

/**
 * This class gathers all the data and skills in order to produce a list of possible rectification for
 * all the words of its specified text wich aren't present in any of the specified dictionnary
 * 
 * This class doesn't have any purpose without a Text and this is why it can't be instanciate without one.
 * 
 * @author Alec Ermis, Maxime Rihouey
 *
 */
public class SpellChecker {

	private Text text;
	private GroupOfDictionary dictionaries;
	/*
	 a HashMap linking words not found in the dictionaries to their possible correction
	 */
	private HashMap<Word, HashSet<String>> wrongWords;

	// constructors
	public SpellChecker(Text text){
		this.text = text;
		dictionaries = new GroupOfDictionary();
		wrongWords = new HashMap<Word, HashSet<String>>();
	}

	public SpellChecker(Text text, GroupOfDictionary dictionaries){
		this.text = text;
		this.dictionaries = dictionaries;
		wrongWords = new HashMap<Word, HashSet<String>>();
	}

	// getters
	public GroupOfDictionary getGroupOfDictionaries(){
		return dictionaries;
	}

	public Text getText(){
		return text;
	}

	// methods

	/**
	 * the specified text replace the actual text and is saved in the text file, then the list of wrong words is emptied
	 */
	public void updateText(String newText){
		this.text = this.text.update(newText);
		wrongWords = new HashMap<Word, HashSet<String>>();

	}

	/**
	 * add a dictionary to the group
	 * @param dictionary
	 */
	public void addDictionary(Dictionary dictionary){
		dictionaries.add(dictionary);
	}

	/**
	 * update the list of wrongwords
	 */
	public HashMap<Word, HashSet<String>> correct(){
		for(Word word : text.getWords()){
			if(!word.isChecked()){
				// in case the word is a the start of a sentence we have to check the word without an upper cased first letter
				if(dictionaries.contains(word.getWord()) || dictionaries.contains(word.getWord().toLowerCase())){
					word.markAsChecked();
				}else{
					if(!wrongWords.containsKey(word)){
						// on crée la liste des mots possibles
						wrongWords.put(word, this.createGroupOfAlternatives(word.getWord()));
					}
				}
			}
		}
		return wrongWords;
	}

	/**
	 * create a list of words "near" to the specified word and existing according to the group of dictionaries
	 * @param word
	 * @return
	 */
	private HashSet<String> createGroupOfAlternatives(String word){
		HashSet<String> liste = new HashSet<String>();
		String tronc1 = "";
		String tronc2 = "";

		for(int i = 0; i < word.length(); i++){
			tronc1 = word.substring(0, i);
			tronc2 = word.substring(i+1, word.length());

			// 1. suppression d'une lettre
			if(dictionaries.contains(tronc1+tronc2)){
				liste.add(tronc1+tronc2);
			}

			// 2. ajout d'une lettre
			for(char lettre = 'A'; lettre <= 'Z'; lettre++){
				if(dictionaries.contains(tronc1+word.charAt(i)+lettre+tronc2)){
					liste.add(tronc1+word.charAt(i)+lettre+tronc2);
				}
			}
			for(char lettre = 'a'; lettre <= 'z'; lettre++){
				if(dictionaries.contains(tronc1+word.charAt(i)+lettre+tronc2)){
					liste.add(tronc1+word.charAt(i)+lettre+tronc2);
				}
			}

			// 3. remplacer une lettre
			for(char lettre = 'A'; lettre <= 'Z'; lettre++){
				if(dictionaries.contains(tronc1+lettre+tronc2)){
					liste.add(tronc1+lettre+tronc2);
				}
			}
			for(char lettre = 'a'; lettre <= 'z'; lettre++){
				if(dictionaries.contains(tronc1+lettre+tronc2)){
					liste.add(tronc1+lettre+tronc2);
				}
			}

			// 4. permutation
			if(i+1 < word.length()){
				if(dictionaries.contains(tronc1+tronc2.substring(0,1)+word.charAt(i)+tronc2.substring(1))){
					liste.add(tronc1+tronc2.substring(0,1)+word.charAt(i)+tronc2.substring(1));
				}
			}

		}
		return liste;
	}

	/*
	 * Test
	 */
	public static void main(String[] args) {

		System.out.println("Avec ABR");
		boolean useABR = true;
		System.out.println("###################### Test Positif ################");
		try {

			// test positif
			SpellChecker SC = new SpellChecker(new Text(new File("texts/testHelene.txt")));
			SC.addDictionary(new Dictionary(new File("dicts/english.jsc"),useABR));
			SC.correct();
			System.out.println(SC.wrongWords);


		} catch (IOException e) {
			System.out.println("Impossible de trouver le fichier.");
		}

		System.out.println("###################### Test Negatif ################");
		try {

			// test positif
			SpellChecker SC = new SpellChecker(new Text(new File("texts/testHelene.txt")));
			SC.addDictionary(new Dictionary(new File("dicts/english.jsc"),useABR));
			//SC.correct();
			System.out.println(SC.wrongWords);


		} catch (IOException e) {
			System.out.println("Impossible de trouver le fichier.");
		}

		System.out.println("Sans ABR");
		useABR = false;
		System.out.println("###################### Test Positif ################");
		try {

			// test positif
			SpellChecker SC = new SpellChecker(new Text(new File("texts/testHelene.txt")));
			SC.addDictionary(new Dictionary(new File("dicts/english.jsc"),useABR));
			SC.correct();
			System.out.println(SC.wrongWords);


		} catch (IOException e) {
			System.out.println("Impossible de trouver le fichier.");
		}

		System.out.println("###################### Test Negatif ################");
		try {

			// test positif
			SpellChecker SC = new SpellChecker(new Text(new File("texts/testHelene.txt")));
			SC.addDictionary(new Dictionary(new File("dicts/english.jsc"),useABR));
			//SC.correct();
			System.out.println(SC.wrongWords);


		} catch (IOException e) {
			System.out.println("Impossible de trouver le fichier.");
		}

	}
}
